home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '91 / '91 Attendee Contributions / Rotate Src / Rotate.a < prev    next >
Encoding:
Text File  |  1991-06-20  |  13.9 KB  |  489 lines  |  [TEXT/MPS ]

  1. ;    Bitmap rotation routines
  2.  
  3. ;    Copyright © 1989 Bob Spence
  4. ;    All rights reserved.
  5.  
  6.     INCLUDE 'QuickEqu.a'
  7.     INCLUDE 'Traps.a'
  8.  
  9. ;
  10. ; Rotation States
  11. ;
  12. ;    no rotation        rotate 180
  13. ;    (0)    1 2            (X)    4 3
  14. ;        3 4                2 1
  15. ;
  16. ;    mirror            mirror
  17. ;    horizontal        vertical
  18. ;    (H)    2 1            (V)    3 4
  19. ;        4 3                1 2
  20. ;
  21. ;    rotate left        rotate right
  22. ;    (L)    2 4            (R    3 1
  23. ;        1 3                4 2
  24. ;
  25. ;     flip left         flip right
  26. ;  (FL)    1 3           (FR)    4 2
  27. ;        2 4                3 1
  28. ;
  29.  
  30. ;
  31. ;    Rotation State Table
  32. ;
  33. ;              Rotate  Mirror  Mirror  Rotate  Rotate
  34. ;      State       180      Horiz       Vert       Left      Right        FL        FR
  35. ;        0        X        H        V        L        R        FL        FR
  36. ;        H        V        0        X        FL        FR        L        R
  37. ;        V        H        X        0        FR        FL        R        L
  38. ;        X        0        V        H        R        L        FR        FL
  39. ;        L        R        FR        FL        X        0        H        V
  40. ;        R        L        FL        FR        0        X        V        H
  41. ;       FL        FR        R        L        V        H        0        X
  42. ;       FR        FL        L        R        H        V        X        0
  43. ;
  44.  
  45. ; typedef enum {Rot0, RotH, RotV, RotX,
  46. ;                RotL, RotR, RotFR, RotFL} RotationSw;
  47.  
  48. Rot0    EQU    0
  49. RotH    EQU    1
  50. RotV    EQU    2
  51. RotX    EQU    3
  52. RotL    EQU    4
  53. RotR    EQU    5
  54. RotFL    EQU    6
  55. RotFR    EQU    7
  56.  
  57. ; PROCEDURE CalcRotate(OldState, NewRotate: RotationSw): RotationSw;
  58. ; parameter offsets (in Pascal order)
  59. NEW_ROTATE    EQU 4+4
  60. OLD_STATE    EQU NEW_ROTATE+4
  61.  
  62.     EXPORT    CALC_ROTATE
  63. CALC_ROTATE    PROC
  64.     Link    A6,#0
  65.     Move.L    OLD_STATE(A6),D0     ; Get the rotation state
  66.     Lsl.W    #3,D0
  67.     Add.W    NEW_ROTATE(A6),D0 ; Apply the new rotation
  68.     And.W    #$3F,D0
  69.     Move.L    RotState,A0        ; Point to the transformation table
  70.     Move.B    (A0,D0.W),-2(A6) ; Return the resultant rotation state
  71.     Unlk    A6
  72.     Move.L    (sp)+,A0        ; Get return address and
  73.     Add.L    #8,sp            ; pop parameters off stack
  74.     Jmp        (A0)            ; for a Pascal style return
  75.  
  76. RotState    ; Indexed by state and rotation, giving new rotation state
  77.     DC.B     Rot0, RotX, RotH, RotV, RotL, RotR, RotFL,RotFR
  78.     DC.B    RotH, RotV, Rot0, RotX, RotFL,RotFR,RotL, RotR
  79.     DC.B    RotV, RotH, RotX, Rot0, RotFR,RotFL,RotR, RotL
  80.     DC.B    RotX, Rot0, RotV, RotH, RotR, RotL, RotFR,RotFL
  81.     DC.B    RotL, RotR, RotFR,RotFL,RotX, Rot0, RotH, RotV
  82.     DC.B    RotR, RotL, RotFL,RotFR,Rot0, RotX, RotV, RotH    
  83.     DC.B    RotFL,RotFR,RotR, RotL, RotV, RotH, Rot0, RotX
  84.     DC.B    RotFR,RotFL,RotL, RotR, RotH, RotV, RotX, Rot0
  85.  
  86.     ENDPROC
  87.     
  88. ;    The user may also select rotation of the image 90° left, right, or
  89. ;     180° as well as mirroring of the image horizontally and vertically.
  90.  
  91.  
  92.  
  93. ; Register usage
  94. ;    A0 = Input bitmap or current data pointer
  95. ;    A1 = Output bitmap or current data pointer
  96. ;    D0 & D1 = temp variables
  97. ;    D2..D7  = part of 16 word rotation matrix
  98.  
  99. ; Named register storage
  100.  
  101. InBase        EQU A2            ; Input BitMap row base address (when rotated)
  102. OutBase        EQU A2            ; Output BitMap row base address (when mirrored)
  103. InBytes        EQU A3            ; Input BitMap rowBytes
  104. xD0            EQU    A4            ; Temp storage for D0 in D0..D7 data block
  105. xD1            EQU    A5            ; Temp storage for D1 in D0..D7 data block
  106.  
  107. ; Local variable stack offsets
  108.  
  109. RowPtr        EQU    -4            ; Temp storage for output word pointer
  110. LowBound    EQU    RowPtr-4    ; Lowest output word address
  111. HiBound        EQU    LowBound-4    ; Highest output word address
  112. OutBytes    EQU    HiBound-2    ; Output BitMap rowBytes 
  113. InWords        EQU    OutBytes-2    ; Words in an input row (-1 for Dbra))
  114. InRows        EQU    InWords-2    ; Rows in the input BitMap
  115. OutRows        EQU    InRows-2    ; Rows in the output BitMap
  116. WordCnt        EQU    OutRows-2    ; Temp storage for Word loop counter
  117. LOCALSZ        EQU    WordCnt-2    ; Total space needed for local variables
  118.  
  119. ; The following Macros are used to:
  120. ;    Initialize the rotation loops
  121. ;    Load registers with input to transform
  122. ;    Transform the data
  123. ;    Loop thru the data as needed, and return
  124.  
  125. ;    
  126. ; Macros used to rotate a BitMap [left, right, flip left, flip right]
  127. ;
  128. ; Used by LOAD_REGS to fill a D register with the next 2 column words
  129.     MACRO
  130.     LOAD_REG    &Dreg
  131.     Move.W    (A0),&Dreg        ; Get a word
  132.     Add.L    InBytes,A0        ; Drop to next row
  133.     Swap    &Dreg            ; Put it into hi word
  134.     Move.W    (A0),&Dreg        ; Get a word
  135.     Add.L    InBytes,A0        ; Drop to next row
  136.     Swap    &Dreg            ; Restore 1st word low, 2nd word hi
  137.     ENDM
  138.  
  139. ; Establish the tops of the 16 word block rotate loops and
  140. ; load a 16 word block of data to rotate in the D registers
  141.     MACRO
  142.     LOAD_REGS &Loop
  143.     Move.L    A1,RowPtr(A6)    ; Save output's word address
  144. &Loop.Col:                    ; Top of the column loop
  145.     Move.W    InWords(A6),D0    ; Word count to process, this row
  146. &Loop.Row:                    ; Top of the row loop
  147.     Move.W    D0,WordCnt(A6)    ; Save loop counter, we need D0
  148.     Move.L    A0,InBase        ; Save the current input address
  149.     ; generate LOAD_REG D0..D7
  150.     LCLA    &n
  151. &n    SETA    0
  152.     WHILE    &n <= 7 DO
  153.     LOAD_REG D&n
  154. &n    SETA    &n + 1
  155.     ENDW
  156.     Move.L    D0,xD0            ; Save working D0 and D1 regs
  157.     Move.L    D1,xD1
  158.     Add.L    #2,InBase        ; Point to next input word block
  159.     Move.L    InBase,A0        ; Restore the start of input
  160.     Move.W    #15,D0            ; Do 16 Dbra loops
  161. &Loop.Word:                    ; Top of the 16 bit loop
  162.     Swap    D0                ; Save bit loop count, we need a word D0
  163.     ENDM
  164.  
  165. ; Rotate a bit from the left or right (&fr) of each word in Dx
  166. ; into the left or right (&to) of the D0 result word
  167.     MACRO
  168.     RotREG &fr,&to,&Dreg
  169.     Rox&fr..W    #1,&Dreg    ; Get an input bit
  170.     Rox&to..W    #1,D0        ; Set the output bit
  171.     Swap        &Dreg        ; Get the 2nd, hi word
  172.     Rox&fr..W    #1,&Dreg    ; Get the next input bit
  173.     Rox&to..W    #1,D0        ; Set the output bit
  174.     Swap        &Dreg        ; Restore hi and lo words
  175.     ENDM
  176.     
  177. ; Get 16 bits from the 16 Dx words, rotated into D0
  178.     MACRO
  179.     ROT_REGS &fr,&to
  180.     ; generate RotREG D0..D7
  181.     LCLA    &n
  182. &n    SETA    0
  183.     WHILE    &n <= 7 DO
  184.     IF        &n <= 1 THEN
  185.     Move.L    xD&n,D1            ; xD0 and xD1 share D1
  186.     RotREG    &fr,&to,D1
  187.     Move.L    D1,xD&n
  188.     ELSE
  189.     RotREG    &fr,&to,D&n
  190.     ENDIF
  191. &n    SETA    &n+1
  192.     ENDW
  193.     Move.W    D0,(A1)            ; Store the rotated output word
  194.     ENDM
  195.  
  196. ; Check the word, row and column loops, cleanup, and return
  197.     MACRO
  198.     END_ROTATE &Loop,&AdSb1,&AdSb2
  199.     &AdSb1..W OutBytes(A6),A1 ; Add/Subtract to next output row
  200.     Swap    D0                ; Get the bit loop count
  201.     IF &AdSb1 = 'Add' THEN
  202.     CMP.L    HiBound(A6),A1    ; If slop on the bottom been exceeded,
  203.     BGT.s    &Loop.End        ;  we will go to next column
  204.     ELSE
  205.     CMP.L    LowBound(A6),A1    ; If slop on the bottom been rotated up,
  206.     BLT.s    &Loop.End        ;  we will go to next column
  207.     ENDIF
  208.     Dbra    D0,&Loop.Word
  209. &Loop.End
  210.     Move.W    WordCnt(A6),D0    ; Get row width word loop count
  211.     Dbra    D0,&Loop.Row
  212.     &AdSb2..L #2,RowPtr(A6)    ; Add/Sub to next output word of row
  213.     Move.L    RowPtr(A6),A1    ; Restore to start of next output word
  214.     Move.L    InBytes,D0        ; Get the input rowBytes
  215.     Lsl.L    #4,D0            ; A0 has wrapped to 1st column, 2nd word
  216.     Sub.L    InBytes,D0        ; so offset = 15 * InBytes
  217.     Add.L    D0,A0            ; Point to next A0 in word 15 rows beyond
  218.     Sub.W    #16,InRows(A6)    ; Drop down to rotate next 16 rows
  219.     Bgt        &Loop.Col        ; When the rows are zero, we're done
  220.     ENDM
  221. ;
  222. ; Macros to mirror BitMaps [horizontal, vertical, 180°, null]
  223. ;
  224. ; Establish the tops of the mirroring loops
  225.     MACRO
  226.     GET_REG &Loop
  227. &Loop.Col:
  228.     Move.L    A1,OutBase        ; Save the start of output
  229.     Move.W    D1,D2            ; Set the Width loop count
  230. &Loop.Row:
  231.     ENDM
  232.  
  233. ; Transfer a word from input to output, unchanged
  234.     MACRO
  235.     GET_WORD    
  236.     Move.W    (A0)+,D0        ; Just get an input word, it's Ok as is
  237.     Move.W    D0,(A1)+        ; Store the word
  238.     ENDM
  239.  
  240. ; Transfer a word from input to output, bits reversed
  241.     MACRO
  242.     REVERSE_REG    
  243.     Move.W    (A0)+,D3        ; Reverse the 16 bits in word D3 
  244.     LCLA    &n
  245. &n    SETA    0
  246.     WHILE    &n <= 15 DO
  247.     Roxr.W    #1,D3            ; Take a bit from the right
  248.     Roxl.W    #1,D0            ;  and insert it to the left
  249. &n    SETA    &n + 1
  250.     ENDW
  251.     Move.W    D0,-(A1)        ; Store the word
  252.     ENDM
  253.  
  254. ; Check the word, row and column loops, cleanup, and return
  255.     MACRO
  256.     END_MIRROR &Loop,&ASub
  257.                             ; Loop,Add/Sub
  258.     Dbra    D2,&Loop.Row    ; Loop thru row's width
  259.     Move.L    OutBase,A1        ; Restore to start of row
  260.     &ASub..L InBytes,A1        ; Add/Sub to next row
  261.     Sub.W    #1,InRows(A6)    ; Drop to next row
  262.     Bgt.s    &Loop.Col        ; When the rows are zero, we're done
  263.     ENDM
  264.  
  265. ; Shift words left by the slop bits    
  266.     MACRO
  267.     SHIFT_WORDS
  268.     LCLA    &n
  269. &n    SETA    0
  270.     WHILE    &n <= 7 DO
  271.     Move.W    -(A0),D0    ; Get a word in the low word
  272.     Rol.L    D4,D0        ; Shift out the slop bits, round in good ones
  273.     Move.W    D0,(A0)        ; Store good word
  274.     Rol.L    D3,D0        ; Shift remaining good bits to top of long word
  275. &n    SETA    &n + 1
  276.     ENDW
  277.     ENDM    
  278.  
  279. ;
  280. ; The bit rotation routine
  281. ; PROCEDURE Rotate (sourceMap, destMap: bitMap);
  282. ;
  283. ; Initialize loops, jump to specific rotation macros, and return
  284. ;
  285. ; parameter offsets (in Pascal order)
  286. DEST_MAP    EQU 4+4
  287. SOURCE_MAP    EQU DEST_MAP+4
  288. ROTATION    EQU SOURCE_MAP+4
  289.  
  290. Btop         EQU  D1     ; Some BitMap bounds Rect defines
  291. Bleft        EQU  D2    
  292. Bbottom        EQU  D3
  293. Bright        EQU  D4
  294.  
  295.     EXPORT    ROTATE
  296. ROTATE    PROC
  297.     Link    A6,#LOCALSZ              ; Allocate temporary storage
  298.     Movem.L    D2-D7/A2-A5,-(sp)     ; D0-D1/A0-A1 are scratch in Pascal and C
  299.     Move.L    SOURCE_MAP(A6),A2     ; Get the source BitMap address
  300.     Move.L    DEST_MAP(A6),A1          ; Get the destination BitMap address
  301.     Moveq    #0,D0
  302.     Move.L    D0,D1
  303.     Move.W    rowBytes(A2),D1        ; Get the input rowBytes
  304.     Move.L    D1,InBytes            ; Set the row byte count
  305.     Lsr.W    #1,D1                ; Convert to words
  306.     Sub.W    #1,D1                ;  minus 1 (for Dbra)
  307. ;;    Move.W    D1,InWords(A6)
  308.     Movem.W    bounds(A2),D1-D4    ; Get the source bounds Rect
  309.     Move.W    Bright,D0
  310.     Sub.W    Bleft,D0
  311.     Asr.W    #4,D0                ; its words, really
  312.     Move.W    D0,InWords(A6)
  313.     Move.W    Bbottom,D0
  314.     Sub.W    Btop,D0
  315.     Move.W    D0,InRows(A6)        ; Set the input number of rows
  316.     Cmp.B    #RotL,ROTATION(A6)    ; Is the destination not rotated
  317.     Blt.s    NoRotate
  318.     Sub.W    Bright,D0            ; Rotate the bounds Rect
  319.     Add.W    Bleft,D0            ; (Bbottom - Btop) - (Bright - Bleft);
  320.     Sub.W    D0,Bbottom
  321.     Add.W    D0,Bright
  322. NoRotate
  323.     Movem.W    D1-D4,bounds(A1) ; Set the destination bounds Rect
  324.     Move.W    Bbottom,D5
  325.     Sub.W    Btop,D5
  326.     Move.W    D5,OutRows(A6)    ; Set the destination row count
  327.  
  328.     Move.W    Bright,D6        ; Compute rowBytes
  329.     Sub.W    Bleft,D6        ;  forced to word boundary
  330.     Add.W    #15,D6
  331.     Lsr.W    #4,D6            ; (Bright - Bleft + 15) / 16) * 2
  332.     Lsl.W    #1,D6
  333. ;;    Move.W    D6,rowBytes(A1)    ; Set the destination rowBytes
  334.     Move.W    rowBytes(A1),D6    ; Get the destination rowBytes
  335.     Move.W    D6,OutBytes(A6)
  336.     Mulu    D6,D5            ; Compute destination map size
  337.     Addq    #2,D5            ;  rowBytes * (Bbottom - Btop)
  338.     Move.L    D5,D0            ;  plus a fudge word for slop bits
  339.     Addq    #2,D0            ;  plus one more slop word
  340. ;;    _NewPtr                    ; allocate space for bitmap
  341. ;;    Move.L    A0,baseAddr(A1)    ; Set the destination upper left corner
  342.     Move.L    baseAddr(A1),A0    ; Get the destination upper left corner
  343.     Move.L    A0,LowBound(A6)    ; Save lowest output address
  344.     Add.L    D5,A0            ; Point beyond lower right corner
  345.     Move.L    A0,HiBound(A6)    ; Save Highest output address
  346.     Move.L    baseAddr(A2),A0    ; Get the source upper left corner
  347.     Move.W    InWords(A6),D1    ; Set D1 for GET_REG Macro
  348.  
  349.     Moveq    #0,D0
  350.     Move.B    ROTATION(A6),D0    ; Get the rotation type
  351.     And.W    #7,D0            ; Force to legal, We provide no error check, yet
  352.     Add.W    D0,D0
  353.     Move.W    Jump_Table(PC,D0),D0
  354.     Jmp        Jump_Table(PC,D0)
  355.  
  356. Jump_Table
  357.     DC.W    (Rotate_0 - Jump_Table)
  358.     DC.W    (Rotate_H - Jump_Table)
  359.     DC.W    (Rotate_V - Jump_Table)
  360.     DC.W    (Rotate_X - Jump_Table)
  361.     DC.W    (Rotate_L - Jump_Table)
  362.     DC.W    (Rotate_R - Jump_Table)
  363.     DC.W    (Rotate_FL - Jump_Table)
  364.     DC.W    (Rotate_FR - Jump_Table)
  365. ;
  366. ; The Rotation and Mirror Routines
  367. ;
  368. Rotate_0                        
  369.     Move.L        LowBound(A6),A1    ; Point to upper left corner
  370.     GET_REG        loop0
  371.     GET_WORD
  372.     END_MIRROR    loop0,Add
  373.     Bra            Exit_Rotate
  374.  
  375. Rotate_H
  376.     Move.L        LowBound(A6),A1    ; Point beyond upper right corner
  377.     Add.W        InBytes,A1        ; for predecrement of A1 in data stores
  378.     GET_REG        loopH
  379.     REVERSE_REG
  380.     END_MIRROR    loopH,Add
  381.     Bra            Shift_Left        ; shift image left slop bits
  382.  
  383. Rotate_V
  384.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  385.     Sub            #2,A1            ; and never slop adjust
  386.     Sub.W        InBytes,A1
  387.     GET_REG        loopV
  388.     GET_WORD
  389.     END_MIRROR    loopV,Sub
  390.     Bra            Exit_Rotate
  391.  
  392. Rotate_X
  393.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  394.                                 ; for predecrement of A1 in data stores
  395.     Move.L        DEST_MAP(A6),A4          ; Get the destination BitMap address
  396.     Move.W        bounds+right(A4),D3
  397.     Sub.W        bounds+left(A4),D3    ; Number of slop bits on the left
  398.     And.W        #$0F,D3                ; Any slop bits to shift in a word ?
  399.     Sub            #2,A1            ; We don't slop adjust later in Shift_Left
  400.     GET_REG        loopX
  401.     REVERSE_REG
  402.     END_MIRROR    loopX,Sub
  403.     Bra            Shift_Left        ; shift image left slop bits
  404.  
  405. Rotate_L
  406.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  407.     Sub.W        OutBytes(A6),A1    ; Point to lower left corner
  408.     Sub            #2,A1            ; and never slop adjust
  409.     LOAD_REGS    loopL
  410.     ROT_REGS    l,l
  411.     END_ROTATE    loopL,Sub,Add
  412.     Bra            Exit_Rotate
  413.  
  414. Rotate_R
  415.     Move.L        LowBound(A6),A1
  416.     Add.W        OutBytes(A6),A1
  417.     Sub.L        #2,A1            ; Point to upper right corner
  418.     LOAD_REGS    loopR
  419.     ROT_REGS    l,r
  420.     END_ROTATE    loopR,Add,Sub
  421.     Bra            Shift_Left        ; shift image left slop bits
  422.  
  423. Rotate_FL
  424.     Move.L        LowBound(A6),A1    ; Point to upper left corner
  425.     LOAD_REGS    loopFL
  426.     ROT_REGS    l,l
  427.     END_ROTATE    loopFL,Add,Add
  428.     Bra            Exit_Rotate
  429.  
  430. Rotate_FR
  431.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  432.     Sub.L        #2,A1            ; Point to lower right corner
  433.     Move.L        DEST_MAP(A6),A4          ; Get the destination BitMap address
  434.     Move.W        bounds+right(A4),D3
  435.     Sub.W        bounds+left(A4),D3    ; Number of slop bits on the left
  436.     And.W        #$0F,D3                ; Any slop bits to shift in a word ?
  437.     Sub            #2,A1            ; We don't slop adjust later in Shift_Left
  438.     LOAD_REGS    loopFR
  439.     ROT_REGS    l,r
  440.     END_ROTATE    loopFR,Sub,Sub
  441. ;;    Bra            Shift_Left        ; shift image left slop bits
  442.  
  443. ;
  444. ; Routines to shift the BitMap data for any slop around
  445. ; the edges caused by images having heights or widths
  446. ; which are not on word boundaries. Some rotations cause 
  447. ; extra columns or rows to be generated to the left or top
  448. ; of the BitMap, we now must push the image up to the topLeft
  449. ; corner of the Bitmap.
  450. ;
  451. ; Shift left the output BitMap any slop columns
  452. Shift_Left
  453.     Move.L    DEST_MAP(A6),A4          ; Get the destination BitMap address
  454.     Move.W    bounds+right(A4),D3
  455.     Sub.W    bounds+left(A4),D3    ; Number of slop bits on the left
  456.     And.W    #$0F,D3                ; Any slop bits to shift in a word ?
  457.     Beq.s    Exit_Rotate
  458.     Move.L    baseAddr(A4),A0    ; Get the destination upper left corner
  459.     Move.W    OutBytes(A6),D1
  460.     Move.W    OutRows(A6),D2    ; Get the output rows
  461.     Mulu    D1,D2            ; Get total byte size
  462.     Add.L    D2,A0            ; Point to lower right corner
  463.     Lsr.W    #1,D2            ; Convert to words
  464.     Moveq    #16,D4
  465.     Sub.W    D3,D4            ; Number of slop bits
  466.     Move.L    D2,D5
  467.     Lsr.L    #3,D5            ; Loop count in blocks of 8 words
  468.     Move.W    D2,D1
  469.     Neg.W    D1                ; To jump into the loop doing the 
  470.     And.W    #7,D1            ;  block boundary remainder first
  471.     Beq.s    Bit_Loop_End
  472.     Asl.W    #3,D1            ; Multiply by code block size
  473.     Jmp        Bit_loop(PC,D1)    ; Jump into the loop, part way
  474. Bit_loop
  475.     SHIFT_WORDS
  476. Bit_Loop_End
  477.     Dbra    D5,Bit_loop
  478.     
  479. Exit_Rotate
  480.     Movem.L    (sp)+,D2-D7/A2-A5
  481.     Unlk    A6
  482.     Move.L    (sp)+,A0        ; Get return address and
  483.     Add.L    #10,sp            ; pop parameters off stack
  484.     Jmp        (A0)            ; for a Pascal style return
  485.     ENDPROC
  486.     
  487.     END
  488.